package com.pureland.boot.generator;

import com.pureland.common.constants.FormatConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @projectName: pureland_cloud
 * @className: com.pureland.boot.generator.RedisSequenceGenerator
 * @description: 基于Redis的序列号生成器实现类
 * @author: tong.li
 * @createTime: 2021/1/6 16:24
 * @version: v1.0
 * @copyright: 版权所有 李彤 © 2020
 */
@Slf4j
public class RedisSequenceGenerator implements SequenceGenerator {


    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Override
    public String generateByTime(String prefix,KeyRule keyRule, int size) {
        if (keyRule == null) {
            throw new IllegalArgumentException("时间规则不能为空");
        }
        prefix = Objects.isNull(prefix) ? "" : prefix;
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = null;
        String localDate = null;
        if (keyRule == KeyRule.YYYY_MM) {
            localDate = now.format(FormatConstants.getFormatter(FormatConstants.YYYYMM));
            // 每月最后一天清一次
            end = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59);
        } else if (keyRule == KeyRule.YYYY_MM_DD) {
            localDate = now.format(FormatConstants.getFormatter(FormatConstants.YYYYMMDD));
            // 每日清一次
            end = now.withHour(23).withMinute(59).withSecond(59);
        } else if (keyRule == KeyRule.YYYY_MM_DD_HH_MM_SS) {
            localDate = now.format(FormatConstants.getFormatter(FormatConstants.YYYYMMDDHHMMSS));
            // 每秒清一次，适用于并发量大的情况下，并发量小的情况下建议使用按天生成
            end = now.withSecond(59);
        }
        // 计算失效的秒数，释放Redis内存空间
        Long expire = Duration.between(now,end).toMillis();
        String key = StringUtils.join(prefix, localDate);
        Long increment = stringRedisTemplate.opsForValue().increment(key);
        if (expire != null) {
            stringRedisTemplate.expire(key,expire, TimeUnit.MILLISECONDS);
        }
        return StringUtils.join(key, StringUtils.leftPad(increment + "", size, '0'));
    }


    @Override
    public String generateNumber(String key, int size) {
        Long increment = stringRedisTemplate.opsForValue().increment(key);
        return StringUtils.leftPad(increment + "", size, '0');
    }


}
